(function(w) {
    var timeline = {};
    //default configuration
    var defOpts = {
        source: null, //data source
        templateUrl: null, //remote template
        target: '', //id of container
        gitIssue: false,
        lightbox: true,
        render: null
    };

    timeline.init = function(opts) {
        for (key in opts) {
            defOpts[key] = opts[key];
        }
        this.opts = defOpts;
        var self = this;
        if (this.opts.lightbox) {
            timeline.loadCSS('http://lokeshdhakar.com/projects/lightbox2/css/lightbox.css');
            !window.$ && timeline.loadJS('http://cdn.bootcss.com/jquery/2.0.3/jquery.js');
            timeline.loadJS('http://lokeshdhakar.com/projects/lightbox2/js/lightbox-2.6.min.js');
        }
        this.request(this.opts.source, function(events) {
            self.renderPerpare(events);
        });
    };

    timeline.loadJS = function(url) {
        var script = document.createElement('script');
        script.src = url;
        document.getElementsByTagName('head')[0].appendChild(script);
    };

    timeline.loadCSS = function(url) {
        var css = document.createElement('link');
        css.rel="stylesheet";
        css.href = url;
        document.getElementsByTagName('head')[0].appendChild(css);
    };

    timeline.request = function(url, cb, raw) {
        var self = this;
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if (4 === xhr.readyState) {
                if ((xhr.status >= 200 && xhr.status < 300) || 304 === xhr.status) {
                    var resText = xhr.responseText;
                    if (!raw) {
                        var resText = JSON.parse(resText);
                        if (self.opts.gitIssue) {
                            resText = resText.body;
                            resText = resText.replace(/`{3}\w*/gi,'');
                            resText = JSON.parse(resText);
                        }
                    }
                    cb(resText);
                } else {
                    throw new Error('Fail to get ajax data for ' + url);
                }
            }
        };
        xhr.open('get', url, true);
        xhr.send(null);
    }

    timeline.render = function(tpl, data) {
        var output = '<div class="v-timeline">\
                        <div class="v-bar"></div>\
                        <ul class="v-events">';
        var events = data;
        data.events && (events = data.events);
        var len = events.length;
        for (var i = 0; i < len; i++) {
            var evt = events[i];
            var eventHTML = '<li class="v-event-wrap">\
                                <div class="v-event">\
                                    <div class="v-hd">\
                                        <a href="' + evt.target + '" class="v-title" target="_blank">' + evt.title + '</a>\
                                        <time class="v-time">' + evt.time + '</time>\
                                    </div>\
                                    <ul class="v-imgs">';
            var imgsHTML = '';
            var tmpLen = evt.imgs.length;
            for (var j = 0; j < tmpLen; j++) {
                var imgUrl = evt.imgs[j];
                var imgHTML = '<li class="v-img-wrap">\
                                    <a href="' + imgUrl + '" data-lightbox="' + evt.time + '"><img src="' + imgUrl + '" alt=""></a>\
                                </li>';
                imgsHTML += imgHTML;
            }
            var extraHTML = '</ul>';
            evt.sour && (extraHTML += '<p class="v-desc">' + evt.desc + '</p>');
            extraHTML += '</div></li>';
            output += eventHTML + imgsHTML + extraHTML;
        }
        output += '</ul></div>';
        if (this.opts.target) {
            document.getElementById(this.opts.target).innerHTML = output;
        } else {
            throw new Error('Target container is not specified, please set target value');
        }
    }

    timeline.renderPerpare = function(events) {
        var render = this.opts.render;
        if (this.opts.templateUrl) {
            this.request(this.opts.templateUrl, function(tpl){
                render ? render(tpl, events) : timeline.render(tpl, events);
            }, true);
        } else {
            render ? render(tpl, events) : timeline.render(tpl, events);
        }
    }

    w.vtimeline = timeline;
})(window);